﻿using System;
using System.Web.Caching;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.Configuration;
using System.Reflection;
using System.Web;
using System.Web.Compilation;

namespace IntraVision.Web
{
    public static class ControllerFactory
    {
        /// <summary>
        /// Получение нужного нам контроллера по его названию
        /// </summary>
        /// <param name="name">Название контроллера</param>
        /// <returns>IController</returns>
        public static IController GetController(string key)
        {
            //Уберем .ivp из имени контроллера
            if (key.EndsWith(".ivp")) key = key.Remove(key.Length - 4, 4);

            //Получим секцию контроллеров из web.config, если обращение идет по псевдониму.
            NameValueCollection controllerKeys = ConfigurationManager.GetSection("controllers") as NameValueCollection;
            if ( controllerKeys != null && !string.IsNullOrEmpty(controllerKeys[key]))
                key = controllerKeys[key];
            else if (!key.EndsWith("controller",StringComparison.InvariantCultureIgnoreCase)) 
                key += "Controller";

            HttpContext context = HttpContext.Current;
            //Проверим существование кэша контроллеров
            Hashtable controllerTypes = context.Cache["ControllerTypes"] as Hashtable;
            //Если кэш контроллеров не создан - создадим его
            if (controllerTypes == null)
            {
                controllerTypes = new Hashtable();
                context.Cache.Add("ControllerTypes", controllerTypes, null, DateTime.Now.AddYears(1), Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null);
            }

            //Если контроллер нужного нам типа есть в кэше, вернем его
            if (controllerTypes[key] != null)
                return Activator.CreateInstance(controllerTypes[key] as Type) as IController;

            //Если контроллера нужного нам типа нет в кэше, попробуем его создать...
            Type controllerType = BuildManager.GetType(key, false, true);
            if (controllerType == null) return null;
            //... и сохраним в кэше
            controllerTypes[key] = controllerType;

            return Activator.CreateInstance(controllerType) as IController;
        }

        /// <summary>
        /// Gets action for specified controller by method name
        /// </summary>
        /// <param name="controller">IController</param>
        /// <param name="action">action name</param>
        /// <param name="paramCount">number of method parameters</param>
        /// <returns>MethodInfo</returns>
        public static MethodInfo GetAction(IController controller, string action, int paramCount)
        {
            if (controller == null) return null;

            //Trying to get action info from cache
            HttpContext context = HttpContext.Current;
            Hashtable controllerActions = context.Cache["ControllerActions"] as Hashtable;
            if (controllerActions == null)
            {
                controllerActions = new Hashtable();
                context.Cache.Add("ControllerActions", controllerActions, null, DateTime.Now.AddYears(1), Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null);
            }

            //generating action key in format "DefaultController.DefaultAction.0"
            string actionKey = String.Format(CultureInfo.InvariantCulture, "{0}.{1}.{2}", controller.GetType().Name, action, paramCount);
            if (controllerActions[actionKey] != null)
            {
                return controllerActions[actionKey] as MethodInfo;
            }
            
            //Browse controller methods for method with specified name and specified amount of parameters 
            foreach (MethodInfo mi in controller.GetType().GetMethods())
            {
                if (mi.Name.ToLower() != action || mi.GetParameters().Length != paramCount) continue;
                controllerActions[actionKey] = mi;
                return mi;
            }
            return null;
        }
    }
}
